package com.springboot.cli.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.springboot.cli.dao.WordMapper;
import com.springboot.cli.domain.Word;
import com.springboot.cli.service.WordService;
import org.apache.fop.util.ListUtil;
import org.docx4j.jaxb.Context;
import org.docx4j.model.table.TblFactory;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.wml.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.xml.bind.JAXBException;
import java.io.File;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * description:
 *
 * @author huxingjie
 * @date 2023/11/7 19:06
 */
@Service
public class WordServiceImpl implements WordService {
    static org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory();

    @Autowired
    private WordMapper wordMapper;

    @Override
    public List<Word> generateWord() throws Exception {
        File file = new File("d:\\icis.docx");
        if (file.exists()) {
            file.delete();
        } else {
            file.createNewFile();
        }
        List<Word> all = wordMapper.findAll();
        String sys = "ICIS_SYS";
        String config = "ICIS_CONFIG";
        List<String> busi = Lists.newArrayList("ICIS_BUSI", "ICIS_ASSESS");
        List<String> base = Lists.newArrayList("ICIS_BASE", "ICIS_HIS");
        // List<String> log = Lists.newArrayList("ICIS_SYS_LOG");
        //系统基础
        List<Word> sysWords = all.stream().filter(a -> a.getTabName().startsWith(sys)).collect(Collectors.toList());
        List<Word> baseWords = all.stream().filter(a -> {
            String tabName = a.getTabName();
            for (String s : base) {
                boolean b = tabName.startsWith(s);
                if (b) return true;
            }
            return false;
        }).collect(Collectors.toList());
        //业务基础
        List<Word> configWords = all.stream().filter(a -> a.getTabName().startsWith(config)).collect(Collectors.toList());
        List<Word> busiWords = all.stream().filter(a -> {
            String tabName = a.getTabName();
            for (String s : busi) {
                boolean b = tabName.startsWith(s);
                if (b) return true;
            }
            return false;
        }).collect(Collectors.toList());
        //处理word
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
        // Add numbering part
        MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart();
        // ndp.setJaxbElement( (Numbering) XmlUtils.unmarshalString(initialNumbering) );
        // Add some document content
        // mainDocumentPart.addParagraphOfText("Example of restarting numbering");
        mainDocumentPart.addObject(createNumberedParagraph(0, 0, "重症监护数据库表设计", 1));
        //新建一个numer
        NumberingDefinitionsPart ndp = getNumberingDefinitionsPart(mainDocumentPart);
        BigInteger numId = ndp.getJaxbElement().getNum().get(0).getNumId();
        System.out.println("numid: " + numId);
        int writableWidthTwips = wordMLPackage.getDocumentModel().getSections().get(0).getPageDimensions().getWritableWidthTwips();
        ArrayList<List<Word>> allWorlds = Lists.newArrayList(sysWords, baseWords, configWords, busiWords);
        Set<String> processed = Sets.newHashSet();
        for (int i = 0; i < allWorlds.size(); i++) {
            if (i == 0) {
                mainDocumentPart.addObject(
                        createNumberedParagraph(0, 0, "系统基础", 2));
            } else if (i == 1) {
                mainDocumentPart.addObject(
                        createNumberedParagraph(0, 0, "业务基础", 2));
            } else if (i == 2) {
                mainDocumentPart.addObject(
                        createNumberedParagraph(0, 0, "业务配置", 2));
            } else if (i == 3) {
                mainDocumentPart.addObject(
                        createNumberedParagraph(0, 0, "业务", 2));
            }
            List<Word> words = allWorlds.get(i);
            Set<String> strings = processWords(words, mainDocumentPart, writableWidthTwips);
            processed.addAll(strings);
        }
        List<Word> otherWords = all.stream().filter(a -> !processed.contains(a.getTabName())).collect(Collectors.toList());
        mainDocumentPart.addObject(
                createNumberedParagraph(0, 0, "其他", 2));
        processWords(otherWords, mainDocumentPart, writableWidthTwips);
        wordMLPackage.save(file);
        return all;
    }

    // Collectors.groupingBy(CatheterMoniitemRecordDto::getMoniitemCode, HashMap::new,
    //                         Collectors.collectingAndThen(
    //                                 Collectors.toList(),
    //                                 list -> list.stream().sorted(Comparator.comparing(CatheterMoniitemRecordDto::getRecordTime))
    //                                         .collect(Collectors.toList())
    //                         )));
    private Set<String> processWords(List<Word> sysWords, MainDocumentPart mainDocumentPart, int writableWidthTwips) {
        Map<String, List<Word>> tableMap = sysWords.stream().collect(Collectors.groupingBy(Word::getTabName));
        tableMap = tableMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new));

        // //三级
        // NumberingDefinitionsPart ndp3 = getNumberingDefinitionsPart(mainDocumentPart);
        // int newNumId3 = ndp3.getJaxbElement().getNum().get(0).getNumId().intValue();
        // System.out.println("newNumId3   "+newNumId3);
        for (Map.Entry<String, List<Word>> entry : tableMap.entrySet()) {
            List<Word> words = entry.getValue();
            Word word = words.get(0);
            String tabDesc = word.getTabDesc();
            String table = entry.getKey();
            mainDocumentPart.addObject(
                    createNumberedParagraph(1, 0, tabDesc + "（ " + table + "）", 3));
            List<List<String>> list = new ArrayList();
            List<String> head = Lists.newArrayList("字段名称", "中文名称", "数据类型", "可空", "主键", "备注");
            list.add(head);
            for (Word word1 : words) {
                ArrayList<String> objects = Lists.newArrayList();
                objects.add(word1.getField());
                objects.add(word1.getFieldName());
                objects.add(word1.getTypeLen());
                objects.add(word1.getIsNull());
                objects.add(word1.getIsPrim());
                objects.add("");
                list.add(objects);
            }
            Tbl tbl = addTable(list, writableWidthTwips);
            mainDocumentPart.addObject(tbl);
        }
        return tableMap.keySet();
    }

    public Tbl addTable(List<List<String>> data, int writableWidthTwips) {
        int col = data.get(0).size();
        int width = writableWidthTwips / col;
        Tbl tbl = TblFactory.createTable(data.size(), col, width);
        List<Object> rows = tbl.getContent();
        for (int i = 0; i < rows.size(); ++i) {
            Tr tr = (Tr) rows.get(i);
            List<Object> cells = tr.getContent();
            for (int j = 0; j < col; ++j) {
                Tc td = (Tc) cells.get(j);
                P p = new P();
                Text t = new Text();
                t.setValue((String) ((List) data.get(i)).get(j));
                R r = new R();
                // if (i == 0) {
                //     Color color = new Color();
                //     color.setVal("#00aa00");
                //     RPr rPr = new RPr();
                //     rPr.setColor(color);
                //     BooleanDefaultTrue b = new BooleanDefaultTrue();
                //     rPr.setB(b);
                //     r.setRPr(rPr);
                // }
                r.getContent().add(t);
                p.getContent().add(r);
                td.getContent().add(p);
            }
        }
        return tbl;
    }

    private static NumberingDefinitionsPart getNumberingDefinitionsPart(MainDocumentPart mainDocumentPart) {
        try {
            NumberingDefinitionsPart ndp = new NumberingDefinitionsPart();
            mainDocumentPart.addTargetPart(ndp);
            Numbering jaxbElement = ndp.unmarshalDefaultNumbering();
            ndp.setJaxbElement(jaxbElement);
            return ndp;
        } catch (Exception e) {
        }
        return null;
    }

    public R addH(String text, int lv) {
        P p = new P();
        Text t = new Text();
        t.setValue(text);
        R r = new R();
        r.getContent().add(t);
        p.getContent().add(r);
        PPr pPr = new PPr();
        PPrBase.PStyle style = new PPrBase.PStyle();
        style.setVal("Heading" + lv);
        pPr.setPStyle(style);
        return r;
    }

    private static P createNumberedParagraph(long numId, long ilvl, String paragraphText, int hlevel) {
        P p = factory.createP();
        org.docx4j.wml.Text t = factory.createText();
        t.setValue(paragraphText);
        org.docx4j.wml.R run = factory.createR();
        run.getContent().add(t);
        p.getContent().add(run);
        org.docx4j.wml.PPr ppr = factory.createPPr();
        //设置标题
        PPrBase.PStyle style = new PPrBase.PStyle();
        style.setVal("Heading" + hlevel);
        ppr.setPStyle(style);
        p.setPPr(ppr);
        if (numId == 0L) return p;
        // Create and add <w:numPr>
        PPrBase.NumPr numPr = factory.createPPrBaseNumPr();
        ppr.setNumPr(numPr);
        // The <w:ilvl> element
        PPrBase.NumPr.Ilvl ilvlElement = factory.createPPrBaseNumPrIlvl();
        numPr.setIlvl(ilvlElement);
        ilvlElement.setVal(BigInteger.valueOf(ilvl));
        // The <w:numId> element
        PPrBase.NumPr.NumId numIdElement = factory.createPPrBaseNumPrNumId();
        numPr.setNumId(numIdElement);
        numIdElement.setVal(BigInteger.valueOf(numId));
        return p;
    }
}
